#include "UserManager.h"
#include <curl/curl.h>
#include <md5.h>
#include <fstream>
#include <filesystem>
#include <windows.h>
// By Zero123
namespace fs = std::filesystem;

unsigned int UserManager::MAX_HISTORY_COUNT = 10;

// UTF-16 (wchar_t*) 转 UTF-8 std::string
static std::string utf16_to_utf8(const std::wstring& wstr)
{
	if (wstr.empty()) return {};

	int size_needed = WideCharToMultiByte(
		CP_UTF8, 0,
		wstr.data(), (int)wstr.size(),
		nullptr, 0,
		nullptr, nullptr);

	std::string strTo(size_needed, 0);
	WideCharToMultiByte(
		CP_UTF8, 0,
		wstr.data(), (int)wstr.size(),
		&strTo[0], size_needed,
		nullptr, nullptr);
	return strTo;
}

// 获取exe所在路径
static fs::path getExecutableDirectory()
{
	wchar_t wbuffer[MAX_PATH] = { 0 };
	GetModuleFileNameW(NULL, wbuffer, MAX_PATH); // 使用宽字符版本
	std::wstring wpath(wbuffer);
	std::string utf8path = utf16_to_utf8(wpath); // 转成 UTF-8 字符串
	return fs::path(utf8path).parent_path();
}

// 文本字段JSON解析
static UserManager::json loadJson(const std::string& txt)
{
	return UserManager::json::parse(txt, nullptr, true, true);
}

// 文件JSON解析
static UserManager::json loadJson(const std::filesystem::path& filePath)
{
	// 打开文件
	std::ifstream file(filePath, std::ios::binary);
	if (!file.is_open())
	{
		throw std::runtime_error("文件打开失败: " + filePath.string());
	}
	// 读取文件内容到字符串
	std::string content((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
	file.close();
	return UserManager::json::parse(content, nullptr, true, true);
}

// 获取历史文件路径
static fs::path getHistoryFilePath()
{
	return getExecutableDirectory() / "modActivity.json";
}

static UserManager::json _cache = nullptr;

UserManager::json UserManager::GET_USER_HISTORY_LIST()
{
	auto dataArray = json::array();
	auto file = getHistoryFilePath();
	if (fs::is_regular_file(file))
	{
		try
		{
			auto joArray = loadJson(file);
			if (joArray.is_array())
			{
				for (const auto& obj : joArray)
				{
					dataArray.emplace_back({
						{"name", obj.value("name", "Unknow")},
						{"modId", obj.value("modId", "Unknow")},
					});
					//dataArray.push_back(json(
					//	{
					//		{"name", obj.value("name", "Unknow")},
					//		{"modId", obj.value("modId", "Unknow")},
					//	}
					//));
				}
			}
		}
		catch (const std::exception& e)
		{
			std::cerr << e.what() << "\n";
		}
	}
	return dataArray;
}

// 通过内存缓存数据优化高频查询性能
UserManager::json UserManager::CACHE_GET_USER_HISTORY_LIST()
{
	if (_cache.is_null())
	{
		_cache = GET_USER_HISTORY_LIST();
	}
	return _cache;
}

UserManager::json& UserManager::GET_CACHE_USER_HISTORY_REF()
{
	return _cache;
}

void UserManager::SET_USER_HISTORY_LIST(const json& newJo)
{
	if (!newJo.is_array())
	{
		throw std::runtime_error(newJo.dump() + "不是有效的数组类型");
	}
	_cache = nullptr;	// 清理缓存数据
	auto file = getHistoryFilePath();
	auto fileParent = file.parent_path();
	if (!fs::exists(fileParent))
	{
		fs::create_directories(fileParent);
	}
	std::ofstream out(file, std::ios::binary);
	out << newJo.dump();
}

// 增加用户历史搜索信息(已经存在则会重新排序)
void UserManager::ADD_USER_HISTORY(const std::string& modName, const std::string& modId)
{
	auto joArray = CACHE_GET_USER_HISTORY_LIST();
	unsigned int i = 0;
	for (auto&& jo : joArray)
	{
		if (jo.value("modId", "") == modId)
		{
			// 存在历史记录 上移
			if (i == 0)
			{
				// 已经是最后一次访问的数据了 不需要任何操作
				return;
			}
			json tempObj = std::move(jo);
			joArray.erase(joArray.begin() + i);
			joArray.insert(joArray.begin(), std::move(tempObj));
			SET_USER_HISTORY_LIST(joArray);
			return;
		}
		i++;
	}
	// 不存在历史记录 新增数据
	joArray.insert(joArray.begin(), json({
		{"name", modName},
		{"modId", modId}
	}));
	if (joArray.size() > MAX_HISTORY_COUNT)
	{
		joArray.erase(joArray.begin() + MAX_HISTORY_COUNT, joArray.end());
	}
	SET_USER_HISTORY_LIST(joArray);
}

class CURL_WARPER
{
public:
	CURL_WARPER()
	{
		CURLcode res = curl_global_init(CURL_GLOBAL_DEFAULT);
		if (res != CURLE_OK)
		{
			throw std::runtime_error("curl_global_init failed");
		}
	}

	~CURL_WARPER()
	{
		curl_global_cleanup();
	}

	static void init()
	{
		static CURL_WARPER instance;
	}

	static std::string post(const std::string& url, const UserManager::json& args={})
	{
		init();
		std::string outResponse;
		CURL* curl = curl_easy_init();
		if (!curl)
		{
			throw std::runtime_error("CURL初始化失败");
		}

		std::string jsonStr = args.dump();
		struct curl_slist* headers = nullptr;
		headers = curl_slist_append(headers, "Content-Type: application/json");

		curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
		curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
		curl_easy_setopt(curl, CURLOPT_POST, 1L);
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonStr.c_str());

		// 写回调
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, +[](char* ptr, size_t size, size_t nmemb, void* userdata) -> size_t
		{
		std::string& out = *static_cast<std::string*>(userdata);
		out.append(ptr, size * nmemb);
		return size * nmemb;
		});
		curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outResponse);

		CURLcode res = curl_easy_perform(curl);

		// 获取 HTTP 状态码
		long httpCode = 0;
		curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);

		curl_slist_free_all(headers);
		curl_easy_cleanup(curl);
		if (res != CURLE_OK)
		{
			throw std::runtime_error("HTTP Error: " + std::to_string(httpCode) + "\nResponse: " + outResponse);
		}
		return outResponse;
	}
};

// 发包查询指定mod信息 code: 0(ok) message
UserManager::json UserManager::POST_MOD_INFO(const std::string& modId)
{

	MD5 md5;
	std::string salt = "channel_id=5&item_id=" + modId + "&mc#h5page#web";
	md5.add(salt.c_str(), salt.length());
	std::string result = md5.getHash();
	auto ret = CURL_WARPER::post("https://g79apigatewayobt.nie.netease.com/h5/pe-item-detail-v2", {
		{"channel_id", 5},
		{"item_id", modId},
		{"sign", result},
	});
	return json::parse(ret);
}

UserManager::json UserManager::FORMAT_POST_MOD_INFO(const std::string& modId)
{
	try
	{
		auto data = UserManager::POST_MOD_INFO(modId);
		if (data.at("code") != 0)
		{
			data["cpp_state"] = 1;
			data["cpp_error"] = data.value("message", "");
		}
		else
		{
			data["cpp_state"] = 0;
		}
		return data;
	}
	catch(const std::exception& e)
	{
		json jo;
		jo["cpp_state"] = -1;
		jo["cpp_error"] = e.what();
		return jo;
	}
}

#ifdef _USER_MANAGER_TEST

#include "Utils/EnvEncode.h"

int main()
{
	Encoding::initEnvcode();
	try
	{
		auto data = UserManager::POST_MOD_INFO("114514");
		std::cout << data.dump() << "\n";
	}
	catch (const std::exception& e)
	{
		std::cout << e.what() << "\n";
	}
	return 0;
}

#endif